package sym.qrcode.style;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Random;

import sym.qrcode.encoder.ByteMatrix;
import sym.qrcode.encoder.Mosaic;
import sym.qrcode.encoder.MosaicMatrix;
import sym.qrcode.image.ImageMosaicMatrix;
import sym.qrcode.image.OutputImage;

public class SmallIconStyle implements ImageGenerator {

    BufferedImage mosaicImage = null;
    BufferedImage findPatternImage = null;
    OutputImage outputMatrix = null;
    ArrayList<BufferedImage> imageList = null;
    public BufferedImage backgroundImage = null;
    public final static int MARGIN = 2;
    public final static int WHITETHRESHOLD = 210;

    public SmallIconStyle(BufferedImage mosaicImage, OutputImage outputMatrix) {
        this.mosaicImage = new BufferedImage(outputMatrix.getScale(),
                outputMatrix.getScale(), BufferedImage.TYPE_INT_RGB);
        this.mosaicImage.getGraphics().drawImage(
                mosaicImage.getScaledInstance(outputMatrix.getScale(),
                outputMatrix.getScale(), Image.SCALE_SMOOTH), 0, 0,
                null);
        this.outputMatrix = outputMatrix;
        imageList = new ArrayList<BufferedImage>();
        this.imageList.clear();
        this.imageList.add(this.mosaicImage);
    }

    public SmallIconStyle(BufferedImage mosaicImage, OutputImage outputMatrix,
            BufferedImage image) {
        this(mosaicImage, outputMatrix);
        if (image == null) {
            return;
        }
        int scale = outputMatrix.getScale();
        int finalWidth = outputMatrix.getMaxImageWidth() + 2 * MARGIN * scale;
        int finalHeight = outputMatrix.getMaxImageHeight() + 2 * MARGIN * scale;
        int negtiveWidth = outputMatrix.getNegtiveImageWidth();
        int negtiveHeight = outputMatrix.getNegtiveImageHeight();
        this.backgroundImage = new BufferedImage(finalWidth + negtiveWidth, finalHeight + negtiveHeight,
                BufferedImage.TYPE_INT_RGB);
        this.backgroundImage.getGraphics().drawImage(
                image.getScaledInstance(finalWidth + negtiveWidth, finalHeight + negtiveHeight,
                Image.SCALE_SMOOTH), 0, 0, null);
    }

    public SmallIconStyle(BufferedImage mosaicImage, OutputImage outputMatrix,
            BufferedImage bimage, BufferedImage findPatternImage) {
        this(mosaicImage, outputMatrix, bimage);
        if (findPatternImage == null) {
            return;
        }
        this.findPatternImage = new BufferedImage(outputMatrix.getScale(),
                outputMatrix.getScale(), BufferedImage.TYPE_INT_RGB);
        this.findPatternImage.getGraphics().drawImage(
                findPatternImage.getScaledInstance(outputMatrix.getScale(),
                outputMatrix.getScale(), Image.SCALE_SMOOTH), 0, 0,
                null);
    }

    @Override
    public BufferedImage getFinalImage() {
        // TODO Auto-generated method stub
        int scale = outputMatrix.getScale();
        int finalWidth = outputMatrix.getMaxImageWidth() + 2 * MARGIN * scale;
        int finalHeight = outputMatrix.getMaxImageHeight() + 2 * MARGIN * scale;

        int negtiveWidth = outputMatrix.getNegtiveImageWidth();
        int negtiveHeight = outputMatrix.getNegtiveImageHeight();

        BufferedImage resultImage = new BufferedImage(finalWidth + negtiveWidth, finalHeight + negtiveHeight,
                BufferedImage.TYPE_INT_RGB);

        for (int i = 0; i < resultImage.getWidth(); i++) {
            for (int j = 0; j < resultImage.getHeight(); j++) {
                if (backgroundImage != null) {
                    resultImage.setRGB(i, j, backgroundImage.getRGB(i, j));
                } else {
                    resultImage.setRGB(i, j, Color.white.getRGB());
                }
            }

        }
        MosaicMatrix mom = outputMatrix.getQrcode().getMosaicMatrix();
        ByteMatrix matrix = outputMatrix.getQrcode().getMatrix();
        Random r = new Random();
        for (int i = 0; i < matrix.getWidth(); i++) {
            for (int j = 0; j < matrix.getHeight(); j++) {
                if (matrix.get(i, j) != 0) {
                    BufferedImage randomImage = null;

                    randomImage = imageList.get(r.nextInt(imageList.size()));
                    for (int p = 0; p < scale; p++) {
                        for (int q = 0; q < scale; q++) {

                            if (findPatternImage != null
                                    && mom.getMosaics()[j][i].type == Mosaic.CRUCIALFUNC
                                    && (mom.getMosaics()[j][i].func_type == Mosaic.FIND_PATTERN_CENTER || mom.getMosaics()[j][i].func_type == Mosaic.FIND_PATTERN_OUTER)) {
                                resultImage.setRGB(negtiveWidth + MARGIN * scale + i * scale + p,
                                        negtiveHeight + MARGIN * scale + j * scale + q, findPatternImage.getRGB(p, q));
                            } else {
                                if (isWhite(new Color(randomImage.getRGB(p, q)))
                                        && backgroundImage != null) {
                                    resultImage.setRGB(
                                            negtiveWidth + MARGIN * scale + i * scale + p,
                                            negtiveHeight + MARGIN * scale + j * scale + q,
                                            backgroundImage.getRGB(MARGIN * scale
                                            + i * scale + p, MARGIN * scale
                                            + j * scale + q));
                                    continue;
                                }
                                resultImage.setRGB(negtiveWidth + MARGIN * scale + i * scale + p,
                                        negtiveHeight + MARGIN * scale + j * scale + q,
                                        randomImage.getRGB(p, q));
                            }
                        }
                    }
                } else {
                    if (backgroundImage != null) {
                        for (int p = 0; p < scale; p++) {
                            for (int q = 0; q < scale; q++) {
                                resultImage.setRGB(
                                        negtiveWidth + MARGIN * scale + i * scale + p,
                                        negtiveHeight + MARGIN * scale + j * scale + q,
                                        backgroundImage.getRGB(MARGIN * scale
                                        + i * scale + p, MARGIN * scale
                                        + j * scale + q));
                            }
                        }
                    }
                }
            }
        }

        for (ImageMosaicMatrix m : outputMatrix.getMosaicList()) {
            for (int i = 0; i < m.getWidth(); i++) {
                for (int j = 0; j < m.getHeight(); j++) {
                    if (m.getMatrix()[j][i].type == Mosaic.IMAGE) {
                        for (int p = 0; p < scale; p++) {
                            for (int q = 0; q < scale; q++) {
                                if (isWhite(new Color(m.getColorRGB(i * scale
                                        + p, j * scale + q)))) {
                                    if (backgroundImage != null) {
                                        resultImage.setRGB(
                                                negtiveWidth + MARGIN * scale + (m.getX() + i)
                                                * scale + p,
                                                negtiveHeight + MARGIN * scale + (m.getY() + j)
                                                * scale + q,
                                                backgroundImage.getRGB(negtiveWidth + MARGIN
                                                * scale
                                                + (m.getX() + i)
                                                * scale + p, negtiveHeight + MARGIN
                                                * scale
                                                + (m.getY() + j)
                                                * scale + q));
                                        continue;
                                    }
                                }
                                resultImage.setRGB(
                                        negtiveWidth + MARGIN * scale + (m.getX() + i) * scale
                                        + p,
                                        negtiveHeight + MARGIN * scale + (m.getY() + j) * scale
                                        + q,
                                        m.getColorRGB(i * scale + p, j * scale
                                        + q));

                            }
                        }
                    }
                }
            }
        }
        return resultImage;
    }

    private boolean isWhite(Color color) {
        // TODO Auto-generated method stub
        if (color.getRed() > WHITETHRESHOLD && color.getBlue() > WHITETHRESHOLD
                && color.getGreen() > WHITETHRESHOLD) {
            return true;
        }
        return false;
    }

    public void addImage(BufferedImage image) {
        BufferedImage image2 = new BufferedImage(outputMatrix.getScale(),
                outputMatrix.getScale(), BufferedImage.TYPE_INT_RGB);
        image2.getGraphics().drawImage(
                image.getScaledInstance(outputMatrix.getScale(),
                outputMatrix.getScale(), Image.SCALE_SMOOTH), 0, 0,
                null);
        this.imageList.add(image2);
    }
}
